JAX Blog

Wo steht Java?

Nachrichten aus einem bewegten Ökosystem

Jul 11, 2023

Der „2023 State of the Java Ecosystem“-Report von New Relic zeigt interessante Entwicklungen im Java-Umfeld: So hat zum Beispiel Oracle seine Marktdominanz in den letzten Jahren verspielt, Container gehören unter Java zum Standard und Java 17 stellt – gemessen an seiner Beliebtheit – alle in den Schatten. Ein Überblick über den aktuellen Stand und wichtige Ereignisse in der Geschichte von Java.

Sun Microsystems veröffentlichte Java im Jahr 1996, um eine portablere und interaktivere Methode zur Entwicklung moderner Multimediaanwendungen zu bieten. Es entstand die erste plattformunabhängige, objektorientierte Programmiersprache. Bis heute ist sie überaus populär: Java wird in fast allen wichtigen Industrie- und Wirtschaftszweigen eingesetzt, bietet Tausende von Bibliotheken und wird gut unterstützt. Sicherheitsaspekte und Parallelverarbeitung (Threads) spielten von Beginn an eine wichtige Rolle.

Ab 2006 veröffentlichte Sun Teile von Java, wie etwa den Compiler javac und die Hotspot Virtual Machine, sowie später große Teile des Java-SE-Quellcodes zur Erstellung eines JDK (Java Developer Kits) unter der GPU General Public License – ein wichtiger Impuls für die Open-Source-Bewegung. Zugleich rief das Unternehmen die OpenJDK-Community ins Leben, die auf der offiziellen, frei verfügbaren Implementierung der Java-Plattform beruht. Mit der Übernahme von Sun durch Oracle im Jahr 2010 änderte sich zunächst nichts an der Open-Source-Lizenzierung. Oracle investierte weiterhin in die Programmiersprache und in ein umfassendes Ökosystem.

Stay tuned

Regelmäßig News zur Konferenz und der Java-Community erhalten

 

Oracles Marktdominanz ist Geschichte

Indes lassen sich interessante – Oracle-Kritiker:innen nennen es vorhersehbare – Entwicklungen am Markt beobachten. Schon in dem „State of the Java Ecosystem“-Report aus dem Jahr 2020 [1] konstatierte Herausgeber New Relic einen Rückgang von Oracles Dominanz auf dem Java-Markt. New Relic wertet für die Studie Daten von Entwickler:innen aus, die die Observability-Plattform des Unternehmens nutzen, um ihre Softwareanwendungen zu monitoren und zu debuggen. Anonymisierte und verallgemeinerte Daten mehrerer Millionen VMs helfen so, einen Überblick über die Entwicklungen des Java Ökosystems zu erhalten.

Demnach verfügte Oracle im Jahr 2020 über einen Marktanteil von etwa 75 Prozent, Tendenz bereits sinkend. Als zweitbeliebtester Anbieter hatte sich das von der Community geführte AdoptOpenJDK etabliert. Auffällig dabei: Während zu dem Zeitpunkt erst etwa elf Prozent der Nutzer:innen auf die damals neue Version Java 11 migriert waren, liefen bereits gut ein Drittel der AdoptOpenJDK VMs unter Java 11. Das lässt den Schluss zu, dass Anwender:innen die Migration nutzten, um zugleich den Distributor zu wechseln. Der wahrscheinlichste Grund: Oracle hatte eine neue Lizenzierungspolitik eingeführt. Zwar blieb die im Januar 2019 veröffentlichte Oracle Java 8 SE kostenfrei. Für den Support und die Nutzung von Updates sowie Security Patches benötigten kommerzielle Anwender:innen allerdings nun eine kostenpflichtige Lizenz.

Die Kund:innen reagierten verärgert. Dass viele sich gegen ein Lizenzabonnement und für eine Alternative entschieden, wird besonders im aktuellen „State of the Java Ecosystem“-Report [2] deutlich. So sank der Marktanteil von Oracle bis zum Jahr 2022 auf 34 Prozent, aktuell beziehen nur noch etwa 28 Prozent ihr JDK von dem einstigen Marktführer. Diese Position hat nun Amazon mit einem Anteil von etwa 31 Prozent übernommen. Sicher profitiert Amazon dabei von dem seit vielen Jahren stetig wachsenden AWS-Geschäft und der großen Community drumherum. Java Coretto ist eine plattformübergreifende Distribution, die auf OpenJDK basiert und damit auch auf dessen Lizenzierungsrichtlinien (GNU General Public License). Die Auslieferung der neuen Releases geht dabei mit den LTS-Releases von OpenJDK Hand in Hand. Die vierteljährlichen Updates enthalten Bugfixes und Performanceoptimierungen.

Inzwischen hat Oracle seine Lizenzpolitik modifiziert: Seit Java 17, dem bisher letzten LTS-Release, kehrte der Anbieter (beinahe) zu seinem kostenlosen Angebot zurück. Nutzer:innen müssen nun den „No Fee Terms and Conditions“ (NFTC) zustimmen und erhalten dafür kostenlose Updates bis Herbst 2024. Das offizielle Supportende ist allerdings für 2026 terminiert. Wer auch nach 2024 von kostenlosen Updates und Patches profitieren möchte, muss entweder für den Support zahlen oder zügig auf die im Herbst 2023 erscheinende Java-Version 21 LTS migrieren. Nicht nur Amazon weiß indes den Oracle-Lizenz-Wirrwarr für sich zu nutzen. So bauten beispielsweise auch die JDK-Distributoren Eclipse Adoptium und RedHat ihre Marktanteile aus (auf mehr als zwölf und 10,5 Prozent) und sind damit keineswegs nur Nischenanbieter.

LTS für die Produktion, Nicht-LTS zum Experimentieren

Der Wechsel zu einem anderen Distributor steht vor allem dann im Raum, wenn ohnehin auf eine neue Java-Version migriert werden muss oder soll. Seit der Übernahme von Sun Microsystems durch Oracle ließen die neuen Releases zunächst jeweils mehr als drei Jahre auf sich warten. Zwischen dem Erscheinen der Version 8, die, wenn auch nicht offiziell so bezeichnet, als Long-Term-Support-Version gelten kann, und dem Release 11 war lange nicht klar, wann das nächste Java LTS erscheinen würde. Nach Java 9 switchte Oracle seinen Releasezyklus und veröffentlichte fortan halbjährlich neue Major Releases. Was mehr Übersicht und Planungssicherheit bringen sollte, stieß auf ein geteiltes Echo. Befürworter:innen freuten sich über kürzere Wartezeiten auf neue Features und Bugfixes. Kritiker bemängelten die kurzen Supportzeiten der Nicht-LTS-Versionen und zweifelten, ob das ganze Umfeld aus IDEs und Konnektoren hier mithalten könne.

Folglich werden vor allem LTS-Versionen (Java 8, Java 11 und Java 17) in der operativen Anwendungsentwicklung eingesetzt. Die Nicht-LTS-Versionen eignen sich hingegen, um zwischendurch neue Features zu testen und die nächste LTS-Migration zu planen. Diese verständliche Zurückhaltung in produktiven Systemen erklärt, warum noch im Jahr 2020 fast 85 Prozent der Java VMs auf Java 8 liefen (laut der Datenerhebung von New Relic), obwohl Java 11 LTS bereits zwei Jahre erhältlich war. Erst etwa elf Prozent nutzen zu diesem Zeitpunkt bereits Java 11.

SIE LIEBEN JAVA?

Den Core-Java-Track entdecken

 

Dennoch warteten viele Development-Teams nicht bis zum Launch der aktuellen Java-LTS-Version 17, sondern migrierten ihre VMs auf Java 11: Aktuell (im Jahr 2023) laufen mehr als 56 Prozent der Java VMs unter Java 11, knapp ein Drittel ist bisher noch auf Java 8 verblieben. Java 17 scheint sich aber nun dennoch durchzusetzen: Während es mehrere Jahre gedauert hat, bis Java 11 eine entsprechende Akzeptanz erreichte, vervielfachte Java 17 seinen Anteil innerhalb eines Jahres. Basierten im vergangenen Jahr nur etwa ein Prozent der von New Relic ausgewerteten Installationen auf Java 17, waren es im Frühling dieses Jahres bereits neun Prozent. Die Nicht-LTS-Versionen spielen indes die erwähnte Nebenrolle: Die beliebtesten unter ihnen sind Java 14 (knapp 0,6 Prozent Anteil) und Java 15 (gut 0,4 Prozent). Noch weniger Installationen verzeichnen die Versionen 16, 18 und 19.

Entwicklung und Migration: von Frameworks und Open-Source-Managern

Ist die Migration auf eine neue Java-Version aufwendig? Auf diese Frage gibt es keine einfache Antwort, denn viele Faktoren spielen eine Rolle. Grundsätzlich ist hierbei die Plattformunabhängigkeit von Java ein großer Vorteil. Erscheint eine neue Version, werden die IDEs (Integrated Development Environments) zügig angepasst. So werden zum Beispiel bei den meisten Distributionen mit der neuen Version die modifizierten Compiler etwa für die verschiedenen Gerätebetriebssysteme ausgeliefert, sodass die Anwendungen auch mit der neuen Java-Version auf den bisherigen Endgeräten laufen. Dennoch reicht eine einfache Neukompilierung der Anwendungen normalerweise nicht aus. Oft muss der Code angepasst werden, vor allem dann, wenn Drittanwendungen oder Funktionen benutzt werden.

Zudem ist es nicht ganz einfach, die verschiedenen genutzten Frameworks und Java Services im Auge zu behalten. Frameworks haben sich aus den Communities heraus entwickelt – aus Ansammlungen vorgefertigter Codeabschnitte sind ganze Java-Plattformen mit Library-Sammlungen von vordefinierten Klassen und Funktionen geworden –, Entwickler:innen haben die Qual der Wahl. Marktführend ist hier das Spring Boot Framework von VMware, das auf dem vor gut 20 Jahren entwickelten Open Source Framework Spring beruht. Spring Boot liegt das Designprinzip „Konvention vor Konfiguration“ zugrunde. Das bedeutet, dass vorgefertigte Funktionen bereits so vorkonfiguriert sind, dass eigene lauffähige Anwendungen recht einfach entwickelt werden können. So vereinfacht das Framework nicht nur die Entwicklung von Microservices, sondern auch komplexerer Softwaremodule.

Im Zuge technologischer Trends wie Containerisierung und Cloud Computing sind in den letzten Jahren Frameworks entstanden, die mit erweiterten Basiskonzepten arbeiten. SpringBoot gilt als reaktives Framework – auch wenn die Definitionen, was genau unter Reaktivität zu verstehen ist, teils sehr weit auseinandergehen. Gemeinhin meint reaktiv, dass asynchrone Datenströme die Programmierung bestimmen und die Anwendung schließlich auf Ereignisse im Datenstrom reagiert. Frameworks, wie zum Beispiel Quarkus, erfreuen sich wachsender Beliebtheit: Das containernative Framework, das für die Ausführung in einer Kubernetes-Umgebung konzipiert ist, kombiniert imperative (also klassische, ablauforientierte) und reaktive Programmierprinzipien. Der Fokus liegt auf leistungsbezogenen Funktionen, was es interessant für die Entwicklung von Microservices und Cloud-Infrastrukturen macht.

Viele Developer:innen nutzen gleich mehrere Frameworks, um bei der Erstellung der eigenen Anwendungen Zeit zu sparen. Das ist nicht ganz unkompliziert, haben doch vor allem größere Frameworks definierte Regeln und interne Abhängigkeiten. Letztere fließen in den eigenen Java-Code ein, Codeabschnitte verschiedener Frameworks sollten nicht durcheinandergeraten, und die Codes und Bibliotheken müssen auf allen Plattformen gepflegt werden. In manchen, vor allem größeren Unternehmen findet man inzwischen einen dedizierten Open-Source-Manager, der sich um diese Fragen kümmert.

Anwendungen im Containerformat

Die Entwicklungen in Java spiegeln auch die allgemeinen Development-Trends wider. Bereits Java 9 führte einige Funktionen ein, um die Arbeit mit Containern zu verbessern. Werden Anwendungen mit Hilfe von Containertechnologien entwickelt, entsteht eine Kapsel, die alle notwendigen Services für den Betrieb der Anwendung enthält. Damit werden Anwendungen unabhängiger von Betriebssystemen oder Infrastrukturen ausführbar. Liegen dem Betrieb Plattformen wie Kubernetes oder Amazon ECS zugrunde, sind sowieso Container-Images notwendig. Heute wird die Mehrzahl der Java-Anwendungen – etwa 70 Prozent – in Form von Container-Images ausgeliefert.

DIE KUNST DER SOTWARE-ARCHITEKTUR

Architecture & Design-Track entdecken

 

Eine typische Funktion, welche die Arbeit mit Containern erleichtert, ist die Möglichkeit, die Startflag -XX:MaxRAMPercentage zu setzen. Sie ersetzt die genaue Definition einer maximalen Heap-Größe, also der Speicherkapazität, die Java für die Anwendungsausführung reservieren soll. Eigentlich ist die Java Virtual Machine (JVM) als Teil der Java-Runtime-Umgebung dafür zuständig, dass eine Java-Applikation portabel ist und ihr genügend Speicher zur Verfügung steht. Weil Anwendungen immer um begrenzte Ressourcen konkurrieren, prüft die JVM zunächst, welche Ressourcen zur Verfügung stehen, und konfiguriert dann die Java-Anwendungen möglichst optimal. Diese sogenannten Ergonomics sind automatisierte Standards, die auch manuell eingestellt werden können.

Doch containerbasierte Anwendungen funktionieren anders: Es sind kleinere, gekapselte Applikationen, denen alle Ressourcen innerhalb des Containers zur Verfügung stehen. Standardeinstellungen wie etwa die Heap-Größe, die die JVM wählt, um Ressourcen zu schonen und zu teilen, erweisen sich nun als unpassend. Häufig bleiben dabei sogar Ressourcen ungenutzt, weil die JVM beispielsweise nur einen Teil des Heap-Speichers zuweist, obwohl innerhalb des Containers ein wesentlich größerer Anteil sinnvoll wäre. Die Startflag löst das Problem, indem sich nun ein prozentualer Anteil an Speicher zuweisen lässt. Das ist deutlich flexibler und nutzt den vorhandenen Speicher containeroptimiert besser aus.

Immer mehr Entwickler:innen nutzen zudem Multi-Core-Konfigurationen, auch dann, wenn sie containerbasiert entwickeln. Noch läuft mehr als ein Drittel und damit die Mehrheit der Java-Anwendungen mit nur einem Core. Doch die Tendenz ist rückläufig – vor einem Jahr waren es noch mehr als 40 Prozent. Fast genauso viele Anwendungen (knapp 30 Prozent) werden inzwischen entwickelt, um auf acht Cores optimale Performance zu erzielen – ein Anstieg um fast 50 Prozent. Die Arbeit mit Threads – und damit auch das Multithreading, also das parallele Abarbeiten von Prozessen – gehörte von Beginn an zu den überzeugenden Argumenten von Java als Programmiersprache. Doch erst seit Java 8 waren die Fortschritte in diesem Bereich so maßgeblich, dass die Entwicklung von Anwendungen für Multi-Core-Umgebungen praktikabel wurde. Bei nicht containerbasierten Java-Anwendungen ist diese Praktik entsprechend weiter verbreitet.

Garbage Collectoren: von Parallel bis G1

Denkt man über das Thema Speicheroptimierung nach, ist auch das Thema Garbage Collector (GC) von entscheidender Bedeutung. Genau wie die Heap-Konfiguration gehört die Wahl des GC zu den Ergonomics der JVM. Die automatische Garbage Collection ist ein Prozess, der den Heap-Speicher auf nicht verwendete Objekte untersucht, die dann gelöscht werden. So wird zwar wieder Speicher für die Anwendung frei, allerdings verbraucht auch der Prozess selbst Ressourcen – und zwar nicht zu knapp. Die Wahl des richtigen Algorithmus ist deshalb wichtig.

Stay tuned

Regelmäßig News zur Konferenz und der Java-Community erhalten

 

In den Anfangszeiten von Java gab es zunächst nur einen ParallelGC: Die Java-Anwendung musste gestoppt werden, damit der GC die unnützen Objekte ausfindig machen konnte. Alle Anfragen, die während dieser Unterbrechung an die Anwendung gestellt wurden, mussten warten, bis der GC seine Arbeit beendet hatte. Je nach definierter Heap-Größe variierte die Dauer der Unterbrechung. Bis Java 8 war der ParallelGC die Standardform der Müllbeseitigung. Der ParallelGC nutzt mehrere Threads gleichzeitig, was wiederum Overhead erzeugt. Das Pendant, der SerialGC, arbeitet im Prinzip gleich, nutzt aber nur einen Thread. Für clientartige Single-Prozessor-Umgebungen eignet er sich daher besser.

Mit der Java Version 1.2 kam ein GC hinzu, der ein anderes Prinzip nutzt: der Concurrent Mark Sweep GC, kurz CMS. Er arbeitet, zumindest teilweise, „concurrent“ (also gleichzeitig) zur Anwendung. Das hat Vor- und Nachteile: Zum einen werden die notwendigen Pausen deutlich kürzer, zum anderen wird aber die Anwendung langsamer, während der CMS arbeitet. Wahrscheinlich war das der Grund, warum sich nie eine Mehrheit für den CMS entschied, der in Java 8 in seiner letzten Version erschien. Mehr als ein Drittel der JVMs, die unter Java 10 oder einer älteren Version laufen, vertrauen die Aufräumarbeiten dem SerialGC an, knapp 22 Prozent dem CMS und weitere 20 Prozent greifen auf den ParalelGC zurück.

Der Nachfolger des CMS, der Garbage First Garbage Collector (G1), begann seinen Siegeszug ab Version 9. Auch er arbeitet teils concurrent zur Anwendung und teils in Stop-the-World-Pausen. Aber der G1 beruht auf einer anderen Implementierung und beseitigt ein gar nicht so seltenes Problem des CMS: Unter bestimmten Umständen, etwa wenn die Heaps stark fragmentiert sind oder der GC zu viel Zeit für seine Arbeit benötigt, wird eine Full Collection ausgelöst, die dann die Anwendung doch wieder unbefriedigend lange lahmlegt. Das Tuning des CMS, mit dem sich das verhindern ließe, ist kompliziert. Statt größere Regionen auf einmal zu löschen, unterteilt der G1 sein Arbeitsgebiet in kleinere Regionen. Das optimiert den Sammelprozess, und die Anwendung friert seltener ein. Außerdem lässt sich vergleichsweise unkompliziert im Vorfeld festlegen, wie die Aufteilung der CPU-Ressourcen zwischen Anwendung und Müllbeseitigung aussehen soll. Im Zweifel erhält die Anwendung so zumindest immer die definierten Ressourcen.

Dass der G1 derzeit wahrscheinlich der beste Kompromiss zwischen Latency und Throughput ist, zeigen die Nutzerzahlen: Fast zwei Drittel derer, die ihre VMs mit Java 11 oder einer höheren Version betreiben, nutzen den G1. 28 Prozent vertrauen nach wie vor dem SerialGC, und die Anteile von CMS und ParallelGC gehen gegen null. Andere, eher als experimentell zu bezeichnende Garbage Collectors, wie zum Beispiel ZGC und Shenandoah, kommen in Produktionssystemen noch immer kaum zum Einsatz. Beide sind allerdings auch noch jünger und fokussieren sich auf niedrige Pausenzeiten, was in Anwendungsfällen von G1 nicht unbedingt Priorität war. Daher sind beide produktionsreife Versionen eher wenig in Nutzung.

Die Zukunft von Java

Für den Herbst ist der Launch der neuen Java-Version 21 LTS geplant, die Supportunterstützung ist bis 2028, der erweiterte Support bis 2031 terminiert. Sie wird einige verbesserte und neue Features, wie etwa virtuelle (leichtgewichtige) Threads, Verbesserungen im Pattern Matching und String Templates, enthalten. Das Java-Ökosystem wird sich entsprechend weiterentwickeln, mittelfristig ist der Entwicklungspfad damit gesichert.

 

Ob Java eine weit verbreitete Programmiersprache bleibt? Andere Sprachen sind auf dem Vormarsch: So machte beispielsweise Google schon 2017 Kotlin zur zweiten offiziellen Android-Programmiersprache neben Java. Ursprünglich für die JVM entwickelt, bringt die junge Sprache einige interessante Features mit; bei der Programmierung kommen Entwickler:innen mit weniger Code aus. Kotlin ist kompatibel zu Java und kann – durch Übersetzung des Codes in JavaScript – auch fürs Web genutzt werden. Auch das leicht zu erlernende Python ist immer wieder als Java-Alternative im Gespräch. Plattformunabhängige, objektorientierte oder prozedurale Programmierung und schnelle Launches machen Python beliebt. Außerdem steht die Frage im Raum, wie Oracle mit den schrumpfenden Marktanteilen umgehen und welcher Entwicklungsaufwand künftig in Java fließen wird.

Allerdings steht Java keineswegs auf wackeligen Füßen. Beinahe alle großen Tech-Unternehmen nutzen die Sprache ausgiebig selbst und Entwickler:innen können unter zahlreichen Distributionen, JDKs, Drittanwendungen und Supportangeboten wählen. Die Community ist groß und sehr aktiv – zahllose verschiedene Frameworks, Tools, Libraries und ähnliche Werkzeuge unterstützen bei der Entwicklungsarbeit. Auch wenn andere Programmiersprachen hier aufholen oder sich für bestimmte Anwendungsfälle besser eignen – an Java vorbeikommen wird man vorerst nicht.

Die statistischen Zahlen in diesem Beitrag beruhen auf dem Report „2023 State of the Java Ecosystem – an in-depth look at one of the most popular programming languages“ [2].


Links & Literatur

[1] https://newrelic.com/blog/nerd-life/state-of-java

[2] https://newrelic.com/resources/report/2023-state-of-the-java-ecosystem

Alle News der Java-Welt:

Behind the Tracks

Agile, People & Culture
Teamwork & Methoden

Clouds & Kubernetes
Alles rund um Cloud

Core Java & Languages
Ausblicke & Best Practices

Data & Machine Learning
Speicherung, Processing & mehr

DevOps & CI/CD
Deployment, Docker & mehr

Microservices
Strukturen & Frameworks

Performance & Security
Sichere Webanwendungen

Serverside Java
Spring, JDK & mehr

Software-Architektur
Best Practices

Web & JavaScript
JS & Webtechnologien

Digital Transformation & Innovation
Technologien & Vorgehensweisen

Domain-driven Design
Grundlagen und Ausblick

Spring Ecosystem
Wissen in Spring-Technologien

Web-APIs
API-Technologie, Design und Management